#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>

int main(int argc, char const *argv[])
{
    // 默认情况下，系统以行缓冲类型打开了标准输出文件（屏幕终端）stdout
    // 默认情况下，系统以不缓冲类型打开了标准出错文件（屏幕终端）stderr
    fprintf(stdout, "abc"); // "abc" --> 缓冲区 --> 屏幕
    fprintf(stderr, "xyz"); // "abc" --> 屏幕
    pause();

    // 默认情况下，该文件对应的缓冲区类型是全缓冲类型
    FILE *fp = fopen("a.txt", "w");

    // 此时，"abcde" 数据将会被送往缓冲区
    fputs("abcde", fp); // "abcde"  --> 标准IO缓冲区 --> 内核 --> a.txt

    // 以下6种方式，可以将缓冲区中的数据刷新到内核并同步给文件
    // 否则，数据将丢失

    // 1. 填满缓冲区
    // long int n = 0;
    // struct stat info;
    // while(1)
    // {
    //     fputc('a', fp);
    //     n++;

    //     // 以下代码检测的是内核中 file{} 里面的文件位置
    //     // 不是外部存储期（硬盘）中实际文件的位置
    //     // long n = ftell(fp);
    //     // if(n > 0)
    //     //     break;

    //     // 以下代码检测硬盘中文件的大小
    //     stat("a.txt", &info); // info中就存放了硬盘文件的各种属性，包括大小
    //     if(info.st_size > 0)
    //         break;
    // }
    // printf("缓冲区大小是：%ld\n", n);
    // printf("缓冲区大小是：%ld\n", info.st_size);

    // 2. 正常退出
    // return 0; // 在main函数中return
    // exit(0);  // 在任意地方退出
    // pthread_exit(NULL); // 在最后一条线程退出

    // 3. 强制刷新缓冲区数据
    // fflush(fp);

    // 4. 关闭文件
    // fclose(fp);

    // 5. 读取文件时，会自动刷新
    // fgetc(fp);

    // 6. 改变缓冲区类型
    // char buf[100];
    // setvbuf(fp, buf, _IOLBF, 100); // 将文件fp的缓冲区改成buf，并且使之为行缓冲
    // setvbuf(fp, NULL, _IONBF, 0);  // 将文件fp的缓冲区改成不缓冲


    // 不正常退出，若还有残留在缓冲区中的数据，它们将会丢失
    kill(getpid(), SIGKILL); // 自己给自己发一个致命信号

    return 0;
}
